home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / clang / cweb31.zip / EXAMPLES / OEMACS.W < prev    next >
Text File  |  1993-01-10  |  38KB  |  897 lines

  1. \datethis
  2. @i xview_types.w
  3.  
  4. @* Introduction.
  5. This program provides an interface between the GNU Emacs editor and the
  6. OpenWindows environment, using the XView toolkit for interactive graphics.
  7. It is based on \.{emacstool}, a SunView interface written by Jeff Peck
  8. of Sun Microsystems in 1986 and adapted by him in 1988 to \.{xvetool},
  9. an early XView interface. The present code, by Don Knuth, is designed to work
  10. with OpenWindows Version~3 as distributed in 1992, using a Sun Type~4
  11. keyboard.
  12.  
  13. GNU Emacs is a highly portable and versatile program, which does most
  14. of the hard work involved in editing files. Our job is simply twofold:
  15. To get \.{emacs} started in an appropriate window, and to transmit
  16. keyboard and mouse events as sequences of characters that \.{emacs}
  17. can happily consume.  These simple tasks do, however, require us to
  18. get a lot of fussy details right. In fact, this program could not have been
  19. written without a good deal more knowledge about XView than can be found
  20. in the manuals. Fortunately Jeff Peck works for Sun, and his
  21. inside knowledge has provided the necessary clues. (All complaints below
  22. about the XView documentation are based on the reference manuals and
  23. programming manuals available from Sun and from O'Reilly \AM\ Associates, in
  24. the summer of 1992. Let us hope that such problems will not persist;
  25. computer programming should be fun, but some of the code below was
  26. written only after a bitter struggle!)
  27.  
  28. The command-line arguments to \.{oemacs} are either standard XView
  29. arguments, which specify the font and the size and position of the window,
  30. the icon, the colors, etc.; or they are standard arguments of \.{emacs},
  31. which typically specify the file to be edited and a position in that file.
  32. If I decide later to make certain things in \.{oemacs} less hardwired,
  33. I will look for options in the X resource database instead of on the
  34. command line.
  35.  
  36. An important note about using \.{xmodmap} to change the behavior of
  37. certain keys appears below. It makes \.{emacs} more powerful, unless you
  38. have other good uses for those keys. (See the entry for \.{xmodmap}
  39. in the index.)
  40.  
  41. Before using \.{oemacs}, you must compile \.{emacs} with the
  42. \.{sunfns} module (which the \.{Makefile} will do for you if you've
  43. configured it correctly), and you should include the lines
  44. $$\vbox{\halign{\.{#}\hfil\cr
  45. (load-library "sun-mouse")\cr
  46. (load-library "sun-fns")\cr}}$$
  47. in Emacs's file \.{lisp/site-init.el}.
  48.  
  49. Caution: This program was developed and tested with Peck's improved
  50. versions of sun-mouse and sun-fns; these are available from
  51. \.{peck@@sun.com} if not yet part of the GNU distribution.
  52.  
  53. @ We follow the traditional structure of XView applications. The |exit|
  54. statement at the end is important, because \.{oemacs} can be invoked by
  55. the \.{system} command in \TEX/ (when the user has typed \.e in response
  56. to an error message); without |exit(0)|, \TEX/ would complain of trouble
  57. executing this program, although we would simply be terminating the program
  58. without returning any particular value.
  59.  
  60. @c
  61. @<Include header files@>@;
  62. @#
  63. Frame frame; /* the base frame where we will live */
  64. @<Global variables@>@; /* additional globals besides |frame| */
  65. @#
  66. @<Event-handling procedures@>@;
  67. @#
  68. main(argc,argv)
  69.   int argc;@+char *argv[]; /* typical \UNIX/ setup */
  70. {
  71.   @<Special initialization@>;
  72.   @<Install the components and controls of |frame|@>;
  73.   xv_main_loop(frame);
  74.   exit(0);
  75. }
  76.  
  77. @ Including the header file \.{<xview/xview.h>} also causes other
  78. basic header files like \.{<xview/frame.h>}, \.{<xview/icon.h>}, etc.,
  79. to be loaded. We must call the \CEE/ compiler with the flag
  80. \.{-I\$(OPENWINHOME)/include} so that the \CEE/ preprocessor will
  81. find the OpenWindows header files.
  82.  
  83. Some \UNIX/ systems define string functions in \.{<string.h>}, some in
  84. \.{<strings.h>}; the Sun documentation calls for \.{<string.h>}. My
  85. experiments indicate that Sun's compiler and loader work perfectly
  86. well with string functions even when no header files are given, so the
  87. programmer doesn't really have to remember the right name. Similarly,
  88. \.{<stdio.h>} isn't really needed with Sun's \CEE/, unless certain macros
  89. are used. I'll include \.{<string.h>} and \.{<stdio.h>} anyway, in the
  90. spirit of being obedient to the stated rules.
  91.  
  92. @<Include...@>=
  93. #include <string.h>
  94. #include <stdio.h>
  95. #include <xview/xview.h>
  96.  
  97. @* The icon and frame.
  98. First we attach an icon that will appear if the user closes the \.{oemacs}
  99. window later.
  100.  
  101. There are two reasons for doing this first. One is that we might as well
  102. begin with an easy task, in order to get warmed up. The other is that
  103. if we specify the icon {\it after\/} creating the frame, we will unconditionally
  104. override an icon that the user may have specified with the \.{-WI}
  105. option on the command line. (This is one of the little things a
  106. programmer has to turn by trial and error, since the XView documentation
  107. leaves much unsaid.)
  108.  
  109. The colors used in the icon will be inherited from the frame, so they will
  110. be reversed if the user asks for reverse video. I~prefer to have the icon
  111. always in black on a yellow background, so I'm making the color explicit.
  112. (I hope this will work on monochrome displays; it works fine on my
  113. grayscale monitor.)
  114.  
  115. @<Create a frame with the gnu icon@>=
  116. {@+Server_image icon_image=(Server_image)xv_create(NULL,SERVER_IMAGE,@|
  117.        XV_WIDTH,64,XV_HEIGHT,64,SERVER_IMAGE_BITS,icon_bits,NULL);
  118.   Server_image mask_image=(Server_image)xv_create(NULL,SERVER_IMAGE,@|
  119.        XV_WIDTH,64,XV_HEIGHT,64,SERVER_IMAGE_BITS,mask_bits,NULL);
  120.   Cms cms=(Cms)xv_create(NULL,CMS,CMS_SIZE,2,@|
  121.         CMS_NAMED_COLORS,"yellow","black",NULL,NULL);
  122.   Icon icon=(Icon)xv_create(NULL,ICON,@|
  123.        ICON_IMAGE,icon_image,ICON_MASK_IMAGE,mask_image,@|
  124.        WIN_CMS,cms,NULL);
  125.   frame=xv_create(NULL,FRAME,FRAME_ICON,icon,NULL);
  126. }
  127.  
  128. @ @<Include...@>=
  129. #include <xview/cms.h>
  130.  
  131. @ If the user hasn't specified a label with the \.{-Wl} option, we turn off
  132. the header line at the top of the frame. That gives us a chance to see
  133. two more lines of the file \.{emacs} is editing. However, we add a
  134. label of our own; it will show up in the virtual window manager display.
  135.  
  136. @<Remove the frame header, unless the user has specifically requested it@>=
  137. if (xv_get(frame,XV_LABEL)==NULL) /* no label specified */
  138.   xv_set(frame,FRAME_SHOW_HEADER,FALSE,XV_LABEL,"OEMACS",NULL);
  139.  
  140. @ The following icon and mask are derived from the ``what's gnu'' image on the
  141. back cover of the GNU Emacs manual. (This accounts for my black-on-yellow
  142. preference.)
  143.  
  144. @<Global...@>=
  145. unsigned short icon_bits[]={@|
  146.     0x0000,    0x0000,    0x0000,    0x1E00,
  147.     0x0000,    0x0000,    0x0000,    0x0900,@|
  148.     0x001E,    0x0000,    0x0000,    0x0880,
  149.     0x0064,    0x0000,    0x0000,    0x0440,@|
  150.     0x0088,    0x0000,    0x0000,    0x0420,
  151.     0x0110,    0x0000,    0x0000,    0x0210,@|
  152.     0x0220,    0x0000,    0x0000,    0x0210,
  153.     0x0420,    0x0FCF,    0x01C0,    0x0108,@|
  154.     0x0840,    0x1030,    0x8620,    0x0088,
  155.     0x1080,    0x00C0,    0x5810,    0x0084,@|
  156.     0x1080,    0x1F00,    0x2008,    0x0044,
  157.     0x2100,    0xE200,    0x1004,    0x0044,@|
  158.     0x4103,    0x0400,    0x0002,    0x0042,
  159.     0x4204,    0x080E,    0x0001,    0x0042,@|
  160.     0x8200,    0x7830,    0x0020,    0x8082,
  161.     0x8203,    0x9040,    0x0018,    0x4102,@|
  162.     0x8204,    0x2080,    0x07C6,    0x3E04,
  163.     0x8108,    0x410C,    0x0021,    0x8004,@|
  164.     0x8080,    0x8210,    0x03D0,    0x6008,
  165.     0x4041,    0x0420,    0x0008,    0x1810,@|
  166.     0x403E,    0x0820,    0x0FFC,    0x0620,
  167.     0x2000,    0x1040,    0x0002,    0x01C0,@|
  168.     0x1000,    0x608C,    0x0FFF,    0x0060,
  169.     0x0801,    0x8110,    0x0080,    0x8118,@|
  170.     0x0406,    0x0220,    0x1FFF,    0x66E0,
  171.     0x0238,    0x044F,    0x0000,    0xD800,@|
  172.     0x01C0,    0x0890,    0x8FFF,    0x4000,
  173.     0x0300,    0x10A6,    0x4041,    0x6000,@|
  174.     0x1C00,    0x2026,    0x4FFF,    0x6000,
  175.     0x60CC,    0x4026,    0x4001,    0x6000,@|
  176.     0x1F33,    0x8010,    0x8FFF,    0x4000,
  177.     0x0012,    0x000F,    0x0040,    0xC000,@|
  178.     0x0022,    0x4000,    0x07FF,    0x4000,
  179.     0x0024,    0x4000,    0x0000,    0x2000,@|
  180.     0x0024,    0x4818,    0x8FFF,    0xE000,
  181.     0x0024,    0x4907,    0x0040,    0x2000,@|
  182.     0x0044,    0x4900,    0x1FFF,    0xE000,
  183.     0x0044,    0x4900,    0x0000,    0x2000,@|
  184.     0x0044,    0x4900,    0x07FF,    0xE000,
  185.     0x0044,    0x4880,    0x0020,    0x2000,@|
  186.     0x0044,    0x4880,    0x07FF,    0xE000,
  187.     0x0044,    0x4840,    0x0000,    0x2000,@|
  188.     0x0044,    0x2A20,    0x07FF,    0xE000,
  189.     0x0044,    0x2410,    0x0020,    0x2000,@|
  190.     0x0042,    0x2448,    0x0FFF,    0xE000,
  191.     0x0042,    0x2948,    0x0000,    0x2000,@|
  192.     0x0041,    0x1144,    0x07FF,    0xA000,
  193.     0x0041,    0x1144,    0x2010,    0x1000,@|
  194.     0x0021,    0x1126,    0x20FA,    0x1000,
  195.     0x0024,    0x8925,    0x2600,    0x1000,@|
  196.     0x0014,    0x8924,    0xA138,    0x7000,
  197.     0x0016,    0x88A4,    0x9090,    0x6000,@|
  198.     0x000A,    0x44A4,    0x4880,    0xA000,
  199.     0x0002,    0x44A2,    0x4401,    0x2000,@|
  200.     0x0003,    0x4492,    0x2001,    0x4000,
  201.     0x0001,    0x2451,    0x3002,    0x8000,@|
  202.     0x0000,    0xA251,    0x1E05,    0x0000,
  203.     0x0000,    0x2248,    0xA1F9,    0x8000,@|
  204.     0x0000,    0x1648,    0x9002,    0x8000,
  205.     0x0000,    0x1A28,    0x4C02,    0x8000,@|
  206.     0x0000,    0x1220,    0x43FC,    0x8000,
  207.     0x0000,    0x0120,    0x2000,    0x8000,@|
  208.     0x0000,    0x0120,    0x2003,    0x0000,
  209.     0x0000,    0x0150,    0x1FFC,    0x0000
  210. };
  211. unsigned short mask_bits[]={@|
  212.     0x0000,    0x0000,    0x0000,    0x1E00,
  213.     0x0000,    0x0000,    0x0000,    0x0F00,@|
  214.     0x001E,    0x0000,    0x0000,    0x0F80,
  215.     0x007C,    0x0000,    0x0000,    0x07C0,@|
  216.     0x00F8,    0x0000,    0x0000,    0x07E0,
  217.     0x01F0,    0x0000,    0x0000,    0x03F0,@|
  218.     0x03E0,    0x0000,    0x0000,    0x03F0,
  219.     0x07E0,    0x0FCF,    0x01C0,    0x01F8,@|
  220.     0x0FC0,    0x103F,    0x87F0,    0x00F8,
  221.     0x1F80,    0x00FF,    0xDFF0,    0x00FC,@|
  222.     0x1F80,    0x1FFF,    0xFFF8,    0x007C,
  223.     0x3F00,    0xE3FF,    0xFFFC,    0x007C,@|
  224.     0x7F03,    0x07FF,    0xFFFE,    0x007E,
  225.     0x7E04,    0x0FFF,    0xFFFF,    0x007E,@|
  226.     0xFE00,    0x7FFF,    0xFFFF,    0x80FE,
  227.     0xFE03,    0x9FFF,    0xFFFF,    0xC1FE,@|
  228.     0xFE04,    0x3FFF,    0xFFFF,    0xFFFC,
  229.     0xFF08,    0x7FFF,    0xFFFF,    0xFFFC,@|
  230.     0xFF80,    0xFFFF,    0xFFFF,    0xFFF8,
  231.     0x7FC1,    0xFFFF,    0xFFFF,    0xFFF0,@|
  232.     0x7FFF,    0xFFFF,    0xFFFF,    0xFFE0,
  233.     0x3FFF,    0xFFFF,    0xFFFF,    0xFFC0,@|
  234.     0x1FFF,    0xFFFF,    0xFFFF,    0xFFE0,
  235.     0x0FFF,    0xFFFF,    0xFFFF,    0xFFF8,@|
  236.     0x07FF,    0xFFFF,    0xFFFF,    0xFEE0,
  237.     0x03FF,    0xFFFF,    0xFFFF,    0xF800,@|
  238.     0x01FF,    0xFFFF,    0xFFFF,    0xE000,
  239.     0x03FF,    0xFFFF,    0xFFFF,    0xE000,@|
  240.     0x1FFF,    0xFFFF,    0xFFFF,    0xE000,
  241.     0x7FFF,    0xFFFF,    0xFFFF,    0xE000,@|
  242.     0x1F7F,    0xFFFF,    0xFFFF,    0xC000,
  243.     0x001F,    0xFFFF,    0xFFFF,    0xC000,@|
  244.     0x003F,    0xFFFF,    0xFFFF,    0xC000,
  245.     0x003F,    0xFFFF,    0xFFFF,    0xE000,@|
  246.     0x003F,    0xFFFF,    0xFFFF,    0xE000,
  247.     0x003F,    0xFFFF,    0xFFFF,    0xE000,@|
  248.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  249.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  250.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  251.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  252.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  253.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  254.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  255.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  256.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  257.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  258.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  259.     0x007F,    0xFFFF,    0xFFFF,    0xF000,@|
  260.     0x003F,    0xFFFF,    0xFFFF,    0xF000,
  261.     0x003F,    0xFFFF,    0xFFFF,    0xF000,@|
  262.     0x001F,    0xFFFF,    0xFFFF,    0xF000,
  263.     0x001F,    0xFFFF,    0xFFFF,    0xE000,@|
  264.     0x000B,    0xFFFF,    0xFFFF,    0xE000,
  265.     0x0003,    0xFFFF,    0xFFFF,    0xE000,@|
  266.     0x0003,    0xFFFF,    0xFFFF,    0xC000,
  267.     0x0001,    0xFFFF,    0xFFFF,    0x8000,@|
  268.     0x0000,    0xBFF1,    0xFFFF,    0x0000,
  269.     0x0000,    0x3FF8,    0xFFFF,    0x8000,@|
  270.     0x0000,    0x1FF8,    0xFFFF,    0x8000,
  271.     0x0000,    0x1FF8,    0x7FFF,    0x8000,@|
  272.     0x0000,    0x13E0,    0x7FFF,    0x8000,
  273.     0x0000,    0x01E0,    0x3FFF,    0x8000,@|
  274.     0x0000,    0x01E0,    0x3FFF,    0x0000,
  275.     0x0000,    0x0150,    0x1FFC,    0x0000
  276. };
  277.  
  278. @* Emulating a terminal.
  279. We will run \.{emacs} in a ``tty subwindow,'' named after the teletype
  280. terminals of ancient yore.
  281.  
  282. The |argv| array will be a command line that invokes
  283. \.{emacs} with all arguments not removed by |xv_init|, i.e., all arguments
  284. that remain after generic XView arguments have been removed.
  285.  
  286. We have to say |WIN_IS_CLIENT_PANE|, otherwise fonts specified on the
  287. command line will be ignored. (This cryptic instruction is mentioned briefly
  288. in the XView reference manual, but not in the XView programming manual;
  289. I~would never have discovered it without Jeff Peck's help.)
  290.  
  291. We also have to set |TTY_QUIT_ON_CHILD_DEATH| to |TRUE|. Otherwise when
  292. \.{emacs} exits (via control-X, control-C) there still will be a terminal
  293. window (into which we can type but not access the shell).
  294.  
  295. Before starting \.{emacs} we set the environment variable
  296. \.{TERM} equal to \.{sun}.
  297. This will tell \.{emacs} to initialize itself with the
  298. programs in its source file \.{lisp/term/sun.el}, where special
  299. adaptations for Sun-style terminals have been recorded.
  300.  
  301. @<Put a tty subwindow into the frame@>=
  302. argv[0]="emacs";
  303. putenv("TERM=sun");
  304. tty=(Tty)xv_create(frame,TTY,WIN_IS_CLIENT_PANE,@|
  305.       TTY_QUIT_ON_CHILD_DEATH,TRUE,@|
  306.       TTY_ARGV,argv,NULL);
  307.  
  308. @ @<Global...@>=
  309. Tty tty;
  310.  
  311. @ @<Include...@>=
  312. #include <xview/tty.h>
  313.  
  314. @ The XView manual doesn't tell us that tty subwindows have a view part
  315. and a pseudo-terminal part. (The manual does mention briefly that text
  316. subwindows have views---at the beginning of section 6.3, and indirectly in
  317. one of the examples in the chapter on color.)
  318.  
  319. The view window of an emulated tty will receive keyboard and
  320. mouse events. We need to know its ``handle,'' because we want to
  321. modify XView's default interpretation of many of those events.
  322.  
  323. For example, we want to grab the keyboard focus (i.e., to begin receiving
  324. keyboard input) as soon as the user moves the mouse into the \.{emacs}
  325. window. The normal OpenLook default requires a user to click in the window
  326. first, but that is inefficient in a production book-writing environment.
  327. Us \.{emacs} users would rather type than point.
  328.  
  329. A secret incantation makes the view window accessible. Dear reader,
  330. would you have guessed how to do this, from reading the manuals only,
  331. without looking at Jeff Peck's code? Be honest now.
  332.  
  333. We don't have to enable the notification of other kinds of events;
  334. tty subwindows already do that.
  335.  
  336. @<Prepare to be notified when the mouse enters the window@>=
  337. window=(Xv_window)xv_get(tty,OPENWIN_NTH_VIEW,0);
  338. xv_set(window,WIN_CONSUME_EVENT,LOC_WINENTER,NULL);
  339.  
  340. @ @<Global...@>=
  341. Xv_window window; /* the view window of |tty| */
  342.  
  343. @ If the user has specified reverse video with the \.{-rv} option,
  344. we will reverse black and white in the mouse cursor. This will make it
  345. more visible against a black background.
  346.  
  347. Changing the cursor is another undocumented reason why we need to know
  348. about the tty's view window; nothing changes if we try to attach
  349. the new cursor to |frame| or to |tty| instead of to |window|.
  350.  
  351. @<Change the cursor, to avoid black-on-black@>=
  352. if (rv) {Xv_singlecolor white,black;
  353.   Xv_cursor cursor;
  354.   white.red=white.green=white.blue=255;
  355.   black.red=black.green=black.blue=0;
  356.   cursor=(Xv_cursor)xv_create(NULL,CURSOR,@|
  357.     CURSOR_SRC_CHAR,OLC_BASIC_PTR,CURSOR_MASK_CHAR,OLC_BASIC_MASK_PTR,@|
  358.     CURSOR_FOREGROUND_COLOR,&white,CURSOR_BACKGROUND_COLOR,&black,NULL);
  359.   xv_set(window,WIN_CURSOR,cursor,NULL);
  360. }
  361.  
  362. @ @<Include...@>=
  363. #include <xview/cursor.h> /* we're using the cursor package */
  364.  
  365. @ What is the variable |rv| that was tested in the code above? Good question.
  366. We have to scan for \.{-rv} before |xv_init| looks at the command arguments.
  367.  
  368. @<Scan the command line, setting |rv| nonzero if \.{-rv} is present@>=
  369. rv=0;
  370. {@+int k=argc;
  371.   while (--k>0) if (strcmp(argv[k],"-rv")==0 ||
  372.                      strcmp(argv[k],"-reverse")==0) rv=1;
  373. }
  374.  
  375. @ @<Global...@>=
  376. int rv;
  377.  
  378. @ We need to know the height and width of characters in the font, in order
  379. to convert mouse positions into coordinates that \.{emacs} will like.
  380. If the user has specified a font explicitly, the font will presumably have
  381. a fixed width for all characters; we can learn the relevant dimensions
  382. by calling |xv_get|. But if the user has not specified a font, the
  383. situation is trickier; |xv_get| will report the width of the default
  384. {\it non\/}-fixed-width font, and this will probably differ from the width of
  385. the actual fixed-width font the tty subwindow will choose.
  386.  
  387. Curiously, if we call |xv_find(NULL,FONT,FONT_FAMILY,
  388. FONT_FAMILY_DEFAULT_FIXEDWIDTH,NULL)| {\it before\/} calling |xv_init|,
  389. without even doing anything with the result returned by |xv_find|,
  390. |xv_init| will not install any fonts specified on the command line.
  391. The trick we used for icons---installing the default gnu icon on the first
  392. call to |xv_create|---will therefore fail.
  393.  
  394. Thus, we have to work around two distinct bugs in XView. The solution
  395. is to discover the effects of the user's command line after |xv_init|
  396. has acted and the frame has been set up; we can determine by brute force what
  397. font will go into the tty window. The program below works correctly
  398. even if the command line specifies \.{-scale} \.{large}, say, instead of
  399. specifying a new font explicitly by something like \.{-font} \.{9x15}.
  400.  
  401. While we are cataloguing peculiarities of XView, we might as well mention
  402. that the default character dimensions of the default font (Lucida) are
  403. reported to be $8\times13$ in the 12-point (medium) size, $8\times15$ in the
  404. 14-point (large) size, and $12\times20$ in the 19-point (extralarge) size.
  405. The actual character dimensions in the window come, however, from the
  406. default fixed-width font (Lucida typewriter), and they are $7\times13$,
  407. $9\times15$, and $11\times23$ in the same three sizes. No logical progression
  408. is evident in either the variable-width or the fixed-width dimensions,
  409. although Lucida is a ``scalable font family.''
  410.  
  411. @<Compute the height and width of characters in the font@>=
  412. {
  413.   Xv_font font=(Xv_font)xv_get(frame,XV_FONT);
  414.   Xv_font dfont=(Xv_font)xv_find(NULL,FONT,FONT_FAMILY,
  415.      FONT_FAMILY_DEFAULT,NULL);
  416.   if (strcmp((char*)xv_get(font,FONT_NAME),
  417.              (char*)xv_get(dfont,FONT_NAME))==0) {
  418.     /* the user didn't specify a new font by name */
  419.     dfont=(Xv_font)xv_find(NULL,FONT,FONT_FAMILY,
  420.       FONT_FAMILY_DEFAULT_FIXEDWIDTH,NULL);
  421.         /* this one will be used by the tty window */
  422.   } else dfont=font;
  423.   char_width=(int)xv_get(dfont,FONT_DEFAULT_CHAR_WIDTH);
  424.   char_height=(int)xv_get(dfont,FONT_DEFAULT_CHAR_HEIGHT);
  425. }
  426.  
  427. @ @<Global...@>=
  428. int char_width, char_height; /* character dimensions in the font */
  429.  
  430. @ @<Include...@>=
  431. #include <xview/font.h> /* header for the font package */
  432.  
  433. @ OK, we've figured out how to install a tty subwindow with the right
  434. event mask and the right cursor, and how to calculate the sizes of the
  435. characters it will contain. All that remains is for us to do these
  436. operations in the proper order, and to specify a filter routine that
  437. will monitor and edit all communications between the keyboard and the
  438. Emacs processor in the window.
  439.  
  440. The new ingredient is the filter specification. We tell the XView
  441. notifier to call |filter| when a window event occurs, instead of
  442. letting it call the tty subroutine event handler directly. The parameter
  443. |NOTIFY_SAFE| implies that the window's event handler is
  444. part of XView, not an alien routine.
  445.  
  446. @<Install the components...@>=
  447. @<Scan the command line, setting |rv| nonzero if \.{-rv} is present@>;
  448. xv_init(XV_INIT_ARGC_PTR_ARGV,&argc,argv,NULL);
  449.       /* start XViewing; strip and remember the OpenWin arguments */
  450. @<Create a frame with the gnu icon@>;
  451. @<Remove the frame header...@>;
  452. @<Put a tty subwindow into the frame@>;
  453. @<Prepare to be notified when the mouse enters the window@>;
  454. @<Change the cursor, to avoid black-on-black@>;
  455. @<Compute the height and width of characters in the font@>;
  456. notify_interpose_event_func(window,filter,NOTIFY_SAFE);
  457.  
  458. @* Keyboard events.
  459. The job of an interposed filter function is to look at an event and
  460. either process it ourselves or pass it through (possibly modified)
  461. to its normal recipient. In the first case we return the code
  462. value |NOTIFY_DONE|, since we aren't reporting any errors;
  463. in the second case we call the normal event handler and return the value
  464. it returns to us.
  465.  
  466. An XView event is a data structure that has been partially
  467. interpreted by the XView routines, which add semantic sugar to
  468. the complex union type of X~Window events. We need not look
  469. too far inside an event structure to do the things that concern us.
  470.  
  471. And what is our job? We are looking for three different kinds of events:
  472.  
  473. \smallskip
  474. \itemitem{(1)} When the mouse enters the window,
  475. we want to grab the keyboard focus.
  476.  
  477. \itemitem{(2)} When a mouse button goes up or down, and we have the keyboard
  478. focus, we want to send a coded sequence of characters to \.{emacs}.
  479.  
  480. \itemitem{(3)} When a key goes down, and we have the keyboard focus, we
  481. want to send an appropriate sequence of characters to \.{emacs}.
  482.  
  483. \itemitem{(4)} When the status of the Num Lock indicator light changes, we
  484. will send emacs the command {\tt turn-numlock-on} or {\tt turn-numlock-off},
  485. for reasons described below.
  486.  
  487. \smallskip\noindent Other events, like instructions to repaint or
  488. resize the window, will be passed through without change to the tty window.
  489.  
  490. @<Event-handling...@>=
  491. Notify_value filter(window,event,arg,type)
  492.   Xv_window window; /* the ``client'' on whom we interposed */
  493.   Event *event; /* the data we are filtering */
  494.   Notify_arg arg; /* optional communication parameter between clients */
  495.   Notify_event_type type; /* |NOTIFY_SAFE| or |NOTIFY_IMMEDIATE| */
  496. {@+register int id=event_id(event);
  497. #ifdef DEBUG
  498.   printf("event %d%s, action %d, shift %x, mouse(%d,%d)\n",
  499.     event_id(event),event_is_up(event)?"UP":"DOWN",event->action,
  500.          event_shiftmask(event),event_x(event),event_y(event));
  501. #endif
  502.   @<Update the Num Lock status@>;
  503.   if (id==LOC_WINENTER) @<Grab the keyboard focus and return@>;
  504.   if (event_is_button(event)) @<Translate a mouse event and return@>;
  505.   if (event_is_up(event)) return NOTIFY_DONE; /* key has been released */
  506.   @<Translate a function key into a special escape sequence@>;
  507.   @<Sanitize a keypress event so that unusual semantic actions are removed@>;
  508.   return notify_next_event_func(window,event,arg,type); /* pass it through */
  509. }
  510.  
  511. @ It's easy to take charge of the keyboard and mouse, as soon as the mouse
  512. enters our territory.
  513.  
  514. @<Grab...@>=
  515. {
  516.   win_set_kbd_focus(window,xv_get(window,XV_XID));
  517.   return NOTIFY_DONE;
  518. }
  519.  
  520. @ If the event is not related to mouse buttons or special function keys,
  521. we want to pass it on unchanged, unless its |event_id| is less than 128.
  522. In that case, it represents a character code, and we want to nuke any
  523. semantic ``keyboard acceleration'' actions it might have been assigned
  524. by OpenWindows.
  525.  
  526. We also make the Meta key add 128 here. An undocumented macro
  527. called |event_set_id|, found in \.{<xview/win\_input.h>},
  528. clears the |action| code as desired.
  529.  
  530. @<Sanitize...@>=
  531. if (id<128)
  532.   if (event_meta_is_down(event)) event_set_id(event,id+128);
  533.   else event_set_action(event,ACTION_NULL_EVENT);
  534.  
  535. @* Function keys.
  536. The Sun Type 4 keyboard has lots of keys, and these can be bound to lots
  537. of useful functions when we are \.{emacs}ing to the max. Besides the
  538. letters and punctuation marks of a normal typewriter, there are ten
  539. ``left'' function keys, L1--L10; twelve ``top'' function keys, F1--F12;
  540. fifteen ``right'' function keys, R1--R15; and eight additional keys
  541. labeled Help, Alt, AltGraph, Ins, Del, Enter, $+$, $-$, which we will
  542. pretend have been labeled B1--B8.
  543.  
  544. The L5 key, also known as Front, is controlled by the Open Look
  545. window manager; it makes a window rise above any that might overlap it,
  546. or shoves the window underneath in case it already was on top.
  547.  
  548. The L7 key, aka Open, is likewise preempted by the
  549. window manager. It closes a frame to an icon, or opens an icon.
  550.  
  551. The window manager traps the R2 key and calls it the ``language'' key;
  552. but I have no use for that feature. So I have remapped R2 to the comparatively
  553. useless character $3\over4$, and I will translate it back to R2 below. (The
  554. \.{xmodmap} program allows users to reassign the interpretation of key codes.)
  555. I could have recovered the L5 and L7 keys in the same way, but I like
  556. their functions as they stand. (L5 and L7 still come through if a
  557. Shift, Control, and/or Meta key is down.)
  558.  
  559. I can never remember the difference between Delete and BackSpace, so I
  560. have mapped them both into control-?, ASCII code 127.
  561.  
  562. There are two Shift keys, one at the left and one at the right, which
  563. are best kept indistinguishable from each other. Similarly, the left
  564. and right Meta keys (`\.{\char27}') are essentially identical. There's a
  565. Control key too. These three types of modifier keys generate keypress
  566. events, but we ignore them; the only thing that matters to us is whether
  567. they are currently up or down, when other keys are pressed.
  568.  
  569. \font\ttit=cmitt10
  570. There also are three special keys that do not generate events, so we
  571. never see them. The CapsLock key toggles the Caps Lock light and
  572. changes lowercase letters to uppercase when the light is on. The
  573. NumLock key toggles the Num Lock light and changes the interpretation
  574. of R4--R15 and B4--B8 when that light is on. The Compose key turns the
  575. Compose light on until you type two characters, then it produces a
  576. special symbol if those two characters match a pattern. For example,
  577. when Compose is followed by either \.{a"} or \.{"a} you get the 8-bit
  578. ISO code for {\tt \"a}; when Compose is followed by either \.{th} or
  579. \.{ht} you get the Icelandic thorn; when it's followed by \.{??} you get {\tt
  580. ?`}; \.{c/} and \.{L-} give \rlap{\./}\.c and {\ttit\char`\$}
  581. and so on. (A list of all composition patterns
  582. appears in \.{<X11/Suncompose.h>}, but not in any of the manuals
  583. I've seen.) The light goes off after two characters have been
  584. typed, or if your first character is not composable, or if
  585. you hit Compose again prematurely. If no proper two-character pattern
  586. was specified, only ``up'' events (key releases) are transmitted, and
  587. nothing will pass through to \.{emacs}.
  588.  
  589. One other feature is worth noting: The key between F12 and Delete
  590. produces a backslash `\.\\', or a vertical line `\.{\char125}' when
  591. shifted.  Everybody knows that, but even more is true. If you hold the
  592. AltGraph key down and press this key, it turns out that you get the
  593. broken-bar character `{\tt\hbox to1em{\hss\vbox{\hrule width 1pt height
  594. 3pt\vskip1.5pt\hrule height2pt depth1pt}\hss}}'.  This is the only key that the
  595. engineers chose to endow with three different graphic symbols.
  596.  
  597. A few other anomalies occur; for example, AltGraph-R1 gives ASCII null,
  598. while AltGraph does not affect R4. But I didn't discover any additional
  599. combinations that are either useful or harmful.
  600.  
  601. Once upon a time the Caps Lock key might have affected the |event_shiftmask|
  602. field of an event, but it has no effect now. The shiftmask is always an
  603. even number, contrary to the implications of \.{<xview/win\_input.h>}.
  604.  
  605. @ The function keys will be translated into a four-character code.
  606. First comes control-X; then an asterisk; then a letter, \.{a}--\.{o}
  607. for function numbers 1--15, respectively; and then another letter,
  608. identifying left, right, top, or bottom. The final letter is
  609. ordinarily `\.l', `\.r', `\.t', or `\.b', respectively. But it is `\.L', `\.R',
  610. `\.T', or `\.B' if a Shift key is down. Furthermore the Control key
  611. subtracts 64 from the ASCII code, so you get `\.,', `\.2', `\.4', or
  612. `\."' with Control and no Shift. With both Control and Shift you get
  613. \.{\\C-L}, \.{\\C-R}, \.{\\C-T}, \.{\\C-B}. A Meta key adds another 128
  614. to the code.  Thus, each function key leads to eight possibilities.
  615.  
  616. For example, if F4 is pressed when Control and Shift are down, but not
  617. Meta, the four-letter code is \.{\\C-X*d\\C-T}. The user could type
  618. that sequence of four characters and get the same effect.
  619.  
  620. Shifted function keys sometimes have a nice mnemonic significance.
  621. For example, key R14, also labeled PgDn, is usually bound to the Emacs
  622. operation `\.{scroll-up}', which moves the window down [sic] by one
  623. screenful; we can then bind Shift-R14 to \.{forward-page}, which advances
  624. down to the next page boundary. In \.{cweb-mode}, the next page boundary
  625. is the next \.{@@*}, beginning a major part of the program. Similarly,
  626. it's convenient to bind B7, the keypad `\.+' key, to \.{forward-paragraph}.
  627. Then in \.{cweb-mode}, Shift-B7 goes to the next module (the next
  628. \.{@@\ } or \.{@@*}).
  629.  
  630. A Composed character will be preceded by \.{\\C-Q}, the Emacs `quote'
  631. character, to distinguish it from a character that was generated with the
  632. Meta key down. This also applies to the broken-bar character, which
  633. will incidentally be preceded by AltGraph, which is B3; you'll probably
  634. want to bind B3 to a no-op if broken bars are important to you.
  635.  
  636. @ This program assumes that several key codes have been rebound from
  637. their normal values. Namely, the commands
  638. $$\vbox{\halign{\.{#}\hfil\cr
  639. keysym R2 = threequarters\cr
  640. keysym KP\_Subtract = onehalf\cr
  641. keysym KP\_Add = onequarter\cr
  642. keysym KP\_Enter = threesuperior\cr
  643. keysym KP\_Decimal = twosuperior\cr
  644. keysym KP\_0 = onesuperior\cr}}$$
  645. should be executed by \.{xmodmap}, preferably in the user's \.{.xinitrc} file.
  646. This makes the keys act as $3\over4$, $1\over2$, $1\over4$, $^3$, $^2$, and
  647. $^1$, respectively. The corresponding 8-bit codes are respectively
  648. 190, 189, 188, 179, 178, 185. (By the way, can anybody explain why the ISO
  649. LATIN-1 code has $^0$, $^2$, and $^3$ in the positions of meta-0, meta-2,
  650. and meta-3, while $^1$ is in the position of meta-9?)
  651. @.xmodmap@>
  652.  
  653. We haven't actually bound the keys this way to use them in editing.
  654. We did it to provide linguistically unimportant codes that OpenWindows
  655. wouldn't mess up; its normal conventions make those valuable keys
  656. unusable for editing, except as duplicates for other existing keys.
  657.  
  658. We send \.{turn-numlock-on/off} commands so that \.{emacs} can keep in
  659. synch with the keyboard state. Namely, it will rebind the function
  660. keys B4--B8 to their numeric-keypad equivalents while the Num Lock light is on.
  661.  
  662. On the other hand, our remapping does make the Num Lock
  663. feature useless in other (non-Emacs) applications.  If you don't
  664. rebind the keys as stated, you lose the functionality of R2 and B4--B8,
  665. but \.{oemacs} will still work.
  666.  
  667. The Help key is another special case. We don't want to remap it,
  668. because it gives useful help information with other OpenWindows
  669. applications.  If Help is pressed without the shift or control key,
  670. the |event_id| is zero and the |event_action| is |ACTION_HELP|.
  671. Control-Help is similar, but with |ACTION_TEXT_HELP|. Shift-Help is
  672. more complicated; it invokes `helpopen: starting new Viewer', after
  673. generating an event that has |event_action=WIN_VISIBILITY_NOTIFY|. The
  674. program below considers the Help key B1 to be characterized by any
  675. event with |event_id=0| and either |event_action!=0| or
  676. |event_shiftmask!=CTRLMASK|.
  677.  
  678. @<Translate a function key into a special escape sequence@>=
  679. {@+register int bank='b'; /* |'l'|, |'r'|, |'t'|, or |'b'| */
  680.   register int n; /* function key serial number, |1<=n<=15| */
  681.   if (id>=KEY_LEFT(1)) @<Translate an ordinary function key@>@;
  682.   else if (id>=256) @<Look for Alt or AltGraph@>@;
  683.   else if (id>=128)
  684.     @<Translate a special function key or composed character@>@;
  685.   else if (id>0 ||
  686.           (event_action(event)==0 && event_shiftmask(event)==CTRLMASK))
  687.     goto non_function;
  688.   else n=1; /* Help key */
  689. emit_function_key:@<Emit the code for a function key and |return|@>;
  690. non_function:;
  691. }
  692.  
  693. @ I'm assuming here that the event id codes occur in the order left, right,
  694. top, bottom, and that no higher event codes exist.
  695.  
  696. @<Translate an ordinary function key@>=
  697. {
  698.   if (id<KEY_RIGHT(1)) { /* on the left bank */
  699.     bank='l';@+n=id-KEY_LEFT(0);
  700.   } else if (id<KEY_TOP(1)) { /* on the right bank */
  701.     bank='r';@+n=id-KEY_RIGHT(0);
  702.   } else if (id<KEY_BOTTOM(1)) {
  703.     bank='t';@+n=id-KEY_TOP(0);
  704.   } else n=id-KEY_BOTTOM(0);
  705.   goto emit_function_key;
  706. }
  707.  
  708. @ The event codes examined here appear in \.{<xview/win\_event.h>}
  709. but not in the XView reference manual.
  710.  
  711. @<Look for Alt or AltGraph@>=
  712. if (id==SHIFT_ALT) {
  713.   n=2;@+goto emit_function_key;
  714. } else if (id==SHIFT_ALTG) {
  715.   n=3;@+goto emit_function_key;
  716. } else goto non_function;
  717.  
  718. @ The |ttysw_input| routine sends text to a tty's view window.
  719. The second parameter is a string, not necessarily terminated by
  720. |'\0'| or anything else; the third parameter is the string length.
  721.  
  722. @<Emit the code for a function key and |return|@>=
  723. {
  724.   if (event_shift_is_down(event)) bank-=32;
  725.   if (event_ctrl_is_down(event)) bank-=64;
  726.   if (event_meta_is_down(event)) bank+=128;
  727.   buf[2]=n+'a'-1;
  728.   buf[3]=bank;
  729.   ttysw_input(window,buf,4);
  730.   return NOTIFY_DONE;
  731. }
  732.  
  733. @ @<Global...@>=
  734. char buf[]="\030*??\021"; /* |030| and |021| give control-X, control-Q */
  735.  
  736. @ @<Translate a special function key or composed character@>=
  737. switch (id) {
  738. case 190: bank='r';@+n=2;@+goto emit_function_key;
  739. case 189: n=8;@+goto emit_function_key;
  740. case 188: n=7;@+goto emit_function_key;
  741. case 179: n=6;@+goto emit_function_key;
  742. case 178: n=5;@+goto emit_function_key;
  743. case 185: n=4;@+goto emit_function_key;
  744. default: buf[5]=id; /* composed character or broken-bar */
  745.   ttysw_input(window,buf+4,2);
  746.   return NOTIFY_DONE;
  747. }
  748.  
  749. @* The NumLock key.
  750. The global variable |num_lock_state| will be 0 if the Num Lock indicator
  751. light is off, 1 if it is on. Whenever an event occurs, we check to see
  752. if |num_lock_state| should change; if so, we change it and send an
  753. appropriate command to \.{emacs}.
  754.  
  755. To read the state of the keyboard LED indicator lights, we need an I/O
  756. control command called the |KIOCGLED| ioctl, described on the
  757. man page for \.{kb(4m)}.
  758.  
  759. @<Global...@>=
  760. int num_lock_state;
  761. char turnon[]="\370turn-numlock-on\r", turnoff[]="\370turn-numlock-off\r";
  762. int keyboard; /* file descriptor of \.{/dev/kbd} */
  763.  
  764. @ @<Include...@>=
  765. #include <sys/file.h> /* definition of |O_RDWR| for |open| */
  766. #include <sundev/kbio.h> /* definition of |KIOCGLED| for |ioctl| */
  767.  
  768. @ @d LED_NUM_LOCK 0x1 /* the official definition is in \.{<server/sunevq.h>},
  769.     but that header file includes huge gobs of other stuff */
  770.  
  771. @<Update the Num Lock status@>=
  772. {@+char leds; /* binary encoding of LED lights */
  773.   ioctl(keyboard,KIOCGLED,&leds);
  774.   if ((leds&LED_NUM_LOCK)!=num_lock_state) {
  775.     num_lock_state=leds&LED_NUM_LOCK;
  776.     if (num_lock_state) ttysw_input(window,turnon,17);
  777.     else ttysw_input(window,turnoff,18);
  778.   }
  779. }
  780.  
  781. @ Any ordinary user can apparently open the keyboard as a file. I would
  782. have tried read-only access if read-write had failed; but read-write access
  783. gives a sense of power even though I won't be writing anything.
  784.  
  785. @<Special initialization@>=
  786. keyboard=open("/dev/kbd",O_RDWR);
  787. if (keyboard<0) {
  788.   fprintf(stderr,"%s: Can't open /dev/kbd!\n",argv[0]);
  789.   exit(1);
  790. }
  791.  
  792. @* Mouse events.
  793. When a mouse button is pressed or released, we send \.{emacs} the
  794. codes control-X and ASCII null, followed by a parenthesized list
  795. of four numbers and carriage-return.
  796. For example, as I was typing this paragraph, I
  797. clicked the left mouse button on the screen just for fun; \.{emacs}
  798. received the characters
  799. $$\.{\\030\\0(1 18 28 9999)\\r\\030\\0(129 18 28 141)\\r}$$
  800. as a result (according to `\.{view-lossage}'). I would have received
  801. the same response if I had typed these characters myself, instead
  802. of clicking the mouse.
  803.  
  804. The first of the four numbers identifies the mouse button itself
  805. as the code number 1, 2, or 4 (for left, middle, right), plus 8 if
  806. a Shift key is down, plus 16 if the Control key is down, plus 32
  807. if a Meta key is down, plus 128 if the mouse key is being released
  808. instead of pressed.
  809.  
  810. The second number is the row number in the frame, the top row being
  811. considered row~0.
  812.  
  813. The third number is the column number in the frame, the left column being
  814. considered column~0.
  815.  
  816. The fourth number is the elapsed time between this mouse event and the
  817. previous one, in milliseconds. If the elapsed time was 10 seconds or
  818. more, 9999 is substituted.
  819.  
  820. Macros inside \.{emacs} can use the second and third numbers to
  821. position the cursor. The fourth number can be used to determine if the
  822. user is ``double clicking'' or using ``chords.'' Examples of such
  823. macros appear in the Emacs source file \.{lisp/sun-mouse.el}.
  824.  
  825. Incidentally, the ASCII null character in mouse sequence makes us happy that
  826. the string parameter to |ttysw_input| is not null-terminated.
  827.  
  828. @<Translate a mouse event...@>=
  829. {@+register int button_code,elapsed_time;
  830.   button_code=(id==MS_LEFT? 1: id==MS_MIDDLE? 2: 4);
  831.   if (event_shift_is_down(event)) button_code += 8;
  832.   if (event_ctrl_is_down(event)) button_code += 16;
  833.   if (event_meta_is_down(event)) button_code += 32;
  834.   if (event_is_up(event)) button_code += 128;
  835.   @<Compute the time elapsed since the previous mouse event@>;
  836.   sprintf(mouse_buf+2,"(%d %d %d %d)\r",button_code,@|
  837.       event_x(event)/char_width, event_y(event)/char_height,@|
  838.       elapsed_time);
  839.   ttysw_input(window,mouse_buf,12+strlen(mouse_buf+12)); /* length is at least 12 */
  840.   return NOTIFY_DONE;
  841. }
  842.  
  843. @ @<Global...@>=
  844. char mouse_buf[24]="\030";
  845.  
  846. @ XView's event structure includes |event_time(event)|, which has
  847. type |struct timeval|; this data type is declared in \.{<sys/time.h>},
  848. which is one of the files included automatically as a result of
  849. including \.{<xview/xview.h>}.
  850. A |timeval| structure consists of two |long| integers, |tv_sec| and |tv_usec|,
  851. denoting clock time in seconds and microseconds, respectively.
  852.  
  853. @<Compute the time...@>=
  854. {@+struct timeval now; /* current time */
  855.   long delta_sec, delta_usec; /* difference between current and
  856.                                  previous time */
  857.   now=event_time(event);
  858.   delta_sec=now.tv_sec-prev_mouse_time.tv_sec;
  859.   delta_usec=now.tv_usec-prev_mouse_time.tv_usec;
  860.   if (delta_usec<0) delta_usec+=1000000,delta_sec--;
  861.   if (delta_sec>=10) elapsed_time=9999; /* infinity (or close enough) */
  862.   else elapsed_time=(delta_sec*1000)+(delta_usec/1000);
  863.   prev_mouse_time=now;
  864. }
  865.  
  866. @ @<Global...@>=
  867. struct timeval prev_mouse_time;
  868.  
  869. @* Remaining problems. There's a terribly unfortunate bug in the
  870. present implementation of XView, causing characters of tty subwindows
  871. to be badly painted at crucial times; the rightmost column of pixels
  872. in a character is often clobbered. If I could figure out how to
  873. generate repaint events for the tty subwindow, I might build a mechanism
  874. into \.{oemacs} that does this after the keyboard has been idle for 10
  875. seconds, say.  This would blink the screen; maybe I'll get used to that,
  876. or maybe I'll prefer to refresh the window manually by binding
  877. \.{redraw-display} to the L2 and R1 keys.  In any case a lot of screen
  878. refreshing is necessary at the moment, alas.
  879.  
  880. (Note added later: I doubt if I'll get used to blinking, and the present
  881. method of manual refresh is tolerable so I won't pursue the 10-second
  882. timer idea. I have meanwhile noticed a procedure |wmgr_refreshwindow(window)|
  883. mentioned in \.{<xview/wmgr.h>}; it will presumably refresh any
  884. given window.
  885.  
  886. Another bug, much less serious, occurs when the window is resized.
  887. If the window gets smaller, \.{emacs} isn't told to correct its
  888. assumptions; so it puts information in strange places or offscreen.
  889. (Internally, emacs uses the \.{TIOCGWINSZ} or \.{TIOCSWINSZ} ioctl,
  890. described in the man page for \.{termio}.)
  891. You can work around this by first making the window very small, then
  892. making it large.
  893.  
  894. @* Index.
  895.  
  896.  
  897.